<template>
  <div>
    <el-card>
      <h2>在线网盘上传</h2>
      <uploader ref="uploader" :options="this.options" :fileStatusText="fileStatusText" @file-added="handleFilesAdded"
        @file-error="handleFileError" @file-success="handleFileSuccess" :autoStart="false">
        <uploader-unsupport></uploader-unsupport>
        <uploader-btn class="select-file-btn" :attrs="attrs" ref="uploadBtn">选择文件</uploader-btn>
        <uploader-btn class="select-file-btn" :attrs="attrs" :directory="true" ref="uploadDirBtn">选择目录</uploader-btn>

        <!-- <uploader-list>
                    <div slot-scope="props">
                        <div v-for="(file, i) in props.fileList" :key="i">
                            <uploader-file :list="true" :file="file"></uploader-file>
                        </div>
                    </div>
                </uploader-list> -->
        <uploader-list v-show="panelShow">
          <template v-slot:default="props">
            <div class="file-panel">
              <div class="file-title">
                <span class="title-span">
                  上传列表<span class="count">（{{ props.fileList.length }}）</span>
                </span>
                <div class="operate">
                  <el-button type="text" :title="collapse ? '展开' : '折叠'"
                    :icon="collapse ? 'el-icon-full-screen' : 'el-icon-minus'"
                    @click="collapse ? (collapse = false) : (collapse = true)">
                  </el-button>
                  <el-button @click="handleClosePanel" type="text" title="关闭" icon="el-icon-close">
                  </el-button>
                </div>
              </div>
              <!-- 正在上传的文件列表 -->
              <!-- fileList = {{ props.fileList }} -->
              <el-collapse-transition>

                <ul class="file-list" v-show="!collapse">
                  <li class="file-item" :class="{
                    'custom-status-item': uploadStatus[file.id] !== ''
                  }" v-for="file in props.fileList" :key="file.id">
                    <uploader-file ref="fileItem" :file="file" :list="true"></uploader-file>
                    <!-- 自定义状态 -->
                    <span class="custom-status">{{ uploadStatus[file.id] }}</span>
                  </li>
                  <div class="no-file" v-if="!props.fileList.length">
                    <i class="icon-empty-file"></i> 暂无待上传文件
                  </div>
                </ul>
              </el-collapse-transition>
            </div>
          </template>
        </uploader-list>
      </uploader>

    </el-card>
  </div>

</template>

<script>
import showUploadFileBox from '../components/uploadFile/index';
import SparkMD5 from 'spark-md5'
export default {
  data() {
    return {
      filesLength: 0, //  上传的文件个数
      dropBoxShow: false, //  拖拽上传是否显示
      collapse: false, //	上传文件面板是否折叠
      panelShow: true, //  上传文件面板是否显示
      uploadStatus: {},
      options: {
        target: `/api/filetransfer/uploadfile`, // 上传文件-目标 URL
        chunkSize: 1024 * 1024, //  每个分片的大小
        fileParameterName: 'file', //  上传文件时文件的参数名，默认 file
        maxChunkRetries: 3, //  并发上传数，默认 3
        testChunks: true, //  是否开启分片已存在于服务器的校验
        // 服务器分片校验函数，秒传及断点续传基础
        checkChunkUploadedByResponse: function (chunk, message) {
          console.log('message')
          let objMessage = JSON.parse(message)

          let data = objMessage.data
          if (data.skipUpload) {
            // 分片已存在于服务器中
            return true
          }
          return (data.uploaded || []).indexOf(chunk.offset + 1) >= 0

        },
        headers: {
          // token: this.$common.getCookies(this.$config.tokenKeyName)
          token: '123'
        },
        query() { }
      },
      /**
       * 支持上传什么类型文件
       */
      attrs: {
        accept: '*'
      },
      /**
       *        文件状态文案映射
       */
      fileStatusText: {
        success: '上传成功',
        error: 'error',
        uploading: '上传中',
        paused: '暂停中',
        waiting: '等待中'
      },
    }
  },
  computed: {
    // Uploader	上传组件实例
    uploaderInstance() {
      return this.$refs.uploader.uploader
    },
  },
  methods: {
    /**
* 文件上传成功 回调函数
* @param {object} rootFile 成功上传的文件所属的根 Uploader.File 对象，它应该包含或者等于成功上传文件
* @param {object} file 当前成功的 Uploader.File 对象本身
* @param {string} response 服务端响应内容，永远都是字符串
*/
    handleFileSuccess(rootFile, file, response) {

      console.log('文件上传成功！')
      let result = JSON.parse(response)
      console.log('result')
      console.log(result)

      if (response == '') {
        this.uploadStatus[file.id] = '上传失败'
        return
      }

      let length = result.data.uploaded.length;

      /**
       * 判断分片是否全部上传完成
       */
      if (result.code !== 200 ||
        result.data.uploaded[length-1] !== length
      ) {
        this.$message.error(result.message)
        this.uploadStatus[file.id] = '上传失败'
        console.log(this.uploadStatus)
        console.log('file id = ' + file.id)
        console.log(this.uploadStatus[file.id])
        return;
      } 
      
      this.filesLength--;

    },
    /**
     * 文件上传失败 回调函数
     * @param {object} rootFile 成功上传的文件所属的根 Uploader.File 对象，它应该包含或者等于成功上传文件
     * @param {object} file 当前成功的 Uploader.File 对象本身
     * @param {string} response 服务端响应内容，永远都是字符串
     */
    handleFileError(rootFile, file, response) {
      console.log('文件上传失败')
      this.$message({
        message: response,
        type: 'error'
      })
    },
    /**
     * 添加批量文件的回调函数
     * @description 对单个或批量文件都按此逻辑处理
     * @param {object} files 批量文件信息
     */
    handleFilesAdded(files) {

      console.log('选择上传的文件')
      console.log(files)

      this.computeMD5(files)

      // files.forEach((file) => {
      //     this.dropBoxShow = false
      //     this.panelShow = true
      //     this.collapse = false
      //     this.computeMD5(file)
      // })
    },
    /**
* 计算md5，实现断点续传及秒传
* @param {object} file 文件信息
*/
    computeMD5(file) {
      let fileReader = new FileReader()
      let blobSlice =
        File.prototype.slice ||
        File.prototype.mozSlice ||
        File.prototype.webkitSlice
      let currentChunk = 0
      const chunkSize = 1 * 1024 * 1024
      let chunks = Math.ceil(file.size / chunkSize)
      let spark = new SparkMD5.ArrayBuffer()
      // 文件状态设为"计算MD5"
      this.uploadStatus[file.id] = '计算MD5'
      file.pause()
      loadNext()
      fileReader.onload = (e) => {
        spark.append(e.target.result)
        if (currentChunk < chunks) {
          currentChunk++
          loadNext()
          // 实时展示MD5的计算进度
          this.uploadStatus[file.id] = `校验MD5 ${(
            (currentChunk / chunks) *
            100
          ).toFixed(0)}%`
          this.uploadStatus = JSON.parse(JSON.stringify(this.uploadStatus))
        } else {
          let md5 = spark.end()
          this.calculateFileMD5End(md5, file)
        }
      }
      fileReader.onerror = function () {
        this.$notify({
          title: '错误',
          message: `文件${file.name}读取出错，请检查该文件`,
          type: 'error',
          duration: 2000
        })
        file.cancel()
      }
      function loadNext() {
        let start = currentChunk * chunkSize
        let end = start + chunkSize >= file.size ? file.size : start + chunkSize
        fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end))
      }
    },
    /**
     * 文件MD5计算结束
     * @param {string} md5 文件 MD5 值
     * @param {object} file 文件对象
     */
    calculateFileMD5End(md5, file) {
      // 将自定义参数直接加载uploader实例的opts上
      Object.assign(this.uploaderInstance.opts, {
        query: {
          ...this.params
        }
      })
      file.uniqueIdentifier = md5
      file.resume()
      // 移除自定义状态
      this.uploadStatus[file.id] = ''
      this.uploadStatus = JSON.parse(JSON.stringify(this.uploadStatus))
    },
    /**
     * 关闭上传面板，并停止上传
     */
    handleClosePanel() {
      this.uploaderInstance.cancel()
      this.panelShow = false
      this.callback('cancel')
    }
  },

}

</script>

<style lang="less" scoped>
.file-panel {
  background-color: #fff;
  border: 1px solid #e2e2e2;
  border-radius: 7px 7px 0 0;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);

  .file-title {
    display: flex;
    height: 40px;
    line-height: 40px;
    padding: 0 15px;
    border-bottom: 1px solid #ddd;

    .title-span {
      padding-left: 0;
      margin-bottom: 0;
      font-size: 16px;

      .count {
        color: red;
      }
    }

    .operate {
      flex: 1;
      text-align: right;

      /deep/ .el-button--text {
        color: red;

        i[class^=el-icon-] {
          font-weight: 600;
        }

        &:hover {

          .el-icon-full-screen,
          .el-icon-minus {
            color: red;
          }

          .el-icon-close {
            color: red;
          }
        }
      }
    }
  }

  .file-list {
    position: relative;
    height: 240px;
    overflow-x: hidden;
    overflow-y: auto;
    background-color: #fff;
    font-size: 12px;
    list-style: none;
    //   setScrollbar(6px, #EBEEF5, #C0C4CC);

    .file-item {
      position: relative;
      background-color: #fff;

      /deep/ .uploader-file {
        height: 40px;
        line-height: 40px;

        .uploader-file-progress {
          border: 1px solid red;
          border-right: none;
          border-left: none;
          background: #e1f3d8;
        }

        .uploader-file-name {
          width: 44%;
        }

        .uploader-file-size {
          width: 16%;
        }

        .uploader-file-meta {
          display: none;
        }

        .uploader-file-status {
          width: 30%;
          text-indent: 0;
        }

        .uploader-file-actions>span {
          margin-top: 12px;
        }
      }

      /deep/ .uploader-file[status='success'] {
        .uploader-file-progress {
          border: none;
        }
      }
    }

    .file-item.custom-status-item {
      /deep/ .uploader-file-status {
        visibility: hidden;
      }

      .custom-status {
        position: absolute;
        top: 0;
        right: 10%;
        width: 24%;
        height: 40px;
        line-height: 40px;
      }
    }
  }

  &.collapse {
    .file-title {
      background-color: #E7ECF2;
    }
  }
}

.no-file {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 16px;
}

/deep/.uploader-file-icon {
  display: none;
}

/deep/.uploader-file-actions>span {
  margin-right: 6px;
}
</style>